/*Copyright (C) 2009 Careil Baptiste

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "IO.h"
#include "System.h"
#include <stdlib.h>


#ifdef WIN32
	#include <conio.h>
	#include <windows.h>
	const int WTXT_DEFAULT_VALUE = 7;	//blanc foncé
	const int WBG_DEFAULT_VALUE = 0;	//noir
#else
	#include <stdio.h>
	#include <string.h>
	#include <unistd.h>
	#include <termios.h>
	#include <sys/time.h>
	const char* UTXT_DEFAULT_VALUE = "039";
	const char* UBG_DEFAULT_VALUE = "049";
#endif

//énumération interne
//
typedef enum TYPE {
	TEXT,
	BG,
	RESET
} TYPE;

typedef enum bool {
	false,
	true
} bool;


//fonction externe
///////////////////////////////////////////////////////////
/// Permet d'effacer l'écran
///////////////////////////////////////////////////////////
void CSLP_ClearScreen()
{
	#ifdef WIN32
	system("cls");
	#else
	system("clear");
	#endif
}

/*
 * Fonctions and enumeration to color the console
 */

#ifdef WIN32
//fonction interne
//
//Permet de récupérer le code de couleur de Win32
int SwitchWin32Col(CSLP_COLORTYPE color)
{
	int col;
	switch (color)
	{
		case BLACK:
			col = 0; break;
		case RED:
			col = 4; break;
		case YELLOW:
			col = 6; break;
		case GREEN:
			col = 2; break;
		case BLUE:
			col = 1; break;
		case VIOLET:
			col = 5; break;
		case CYAN:
			col = 3; break;
		case WHITE:
			col = 7; break;
		default:
			col = WTXT_DEFAULT_VALUE;
	}
	return col;
}
#else
//fonction interne
//
//Permet de récupérer le code couleur unix pour le texte
void SwitchUnixCol(CSLP_COLORTYPE color, char* txt)
{
	switch (color)
	{
		case BLACK:
			txt = strcpy(txt, "030"); break;
		case RED:
			txt = strcpy(txt, "031"); break;
		case GREEN:
			txt = strcpy(txt, "032"); break;
		case YELLOW:
			txt = strcpy(txt, "033"); break;
		case BLUE:
			txt = strcpy(txt, "034"); break;
		case VIOLET:
			txt = strcpy(txt, "035"); break;
		case CYAN:
			txt = strcpy(txt, "036"); break;
		case WHITE:
			txt = strcpy(txt, "037"); break;
		default:
			txt = strcpy(txt, UTXT_DEFAULT_VALUE);
	}
}
#endif

//fonction interne
//
//Permet de changer la couleur du text si text = true 
//ou du bg si text = false
void ColorChange(CSLP_COLORTYPE color, TYPE tp)
{
	bool light = false;
	#ifdef WIN32
	static int wbg = 0;	//WBG_DEFAULT_VALUE;
	static int wtxt = 7;	//WTXT_DEFAULT_VALUE;
	HANDLE H = GetStdHandle(STD_OUTPUT_HANDLE);
	#else
	static char ubg[4] = "049";	//=UBG_DEFAULT_VALUE
	static char utxt[4] = "039";	//=UTXT_DEFAULT_VALUE
	char param[8];
	#endif
	
	//on récupère le bit CLAIR
	if ( color >= (int)(LIGHT))
	{
		light = true;
		color -= LIGHT;
	}

	if (tp == TEXT)
	{ //mis à jour de la couleur du texte
		#ifdef WIN32
		if (color == DEFAULT)
		{
			wtxt = WTXT_DEFAULT_VALUE;
		}
		else
		{
			wtxt = SwitchWin32Col(color);
			if (light)
				wtxt+=8;	//on passe au claire
		}
		#else
		SwitchUnixCol(color, utxt);
		if (light)
			utxt[1]='9';	//on passe au claire
		#endif
	}
	else if ( tp == BG)
	{ // mis à jour de la couleur de fond
		#ifdef WIN32
		if (color == DEFAULT)
		{
			wbg = WBG_DEFAULT_VALUE;
		}
		else
		{
			wbg = SwitchWin32Col(color);
			if ( light)
				wbg+=8;	//on passe au claire
			wbg *= 16;	//on passe à l'octet superieur
		}
		#else
		SwitchUnixCol(color, ubg);	//on récupère l'indice pour le texte
		if ( light)
		{
			ubg[0] = '1';
			ubg[1] = '0';
		}
		else
		{
			ubg[1] = '4';	//on passe au BG
		}
		#endif
	}
	else
	{
		#ifdef WIN32
		wbg = 0;
		wtxt = 7;
		#else
		strcpy(ubg, UBG_DEFAULT_VALUE);
		strcpy(utxt, UTXT_DEFAULT_VALUE);
		#endif
	}
	
	//mis à jour de l'affichage
	#ifdef WIN32
	SetConsoleTextAttribute(H, wbg + wtxt);
	#else
	param[0]=utxt[0];
	param[1]=utxt[1];
	param[2]=utxt[2];
	param[3]=';';
	param[4]=ubg[0];
	param[5]=ubg[1];
	param[6]=ubg[2];
	param[7]='\0';
	printf("\033[%sm", param);
	#endif
}

//fonction externe
///////////////////////////////////////////////////////////
/// Permet de réinitialiser les couleurs par défaut de la console
///////////////////////////////////////////////////////////
void CSLP_ResetColors()
{
	#ifdef WIN32
	CSLP_ColorText(WHITE);
	CSLP_ColorBG(BLACK);
	#else
	CSLP_Color(DEFAULT, DEFAULT);
	#endif
	ColorChange(BLACK, RESET);
}

//fonction externe
///////////////////////////////////////////////////////////
/// Permet d'initialiser la couleur de texte de la console
///////////////////////////////////////////////////////////
void CSLP_ColorText(CSLP_COLORTYPE color)
{
	ColorChange(color, TEXT);
}

//fonction externe
///////////////////////////////////////////////////////////
/// Permet d'initialiser la couleur de fond de la console
///////////////////////////////////////////////////////////
void CSLP_ColorBG(CSLP_COLORTYPE color)
{
	ColorChange(color, BG);
}

//fonction externe
///////////////////////////////////////////////////////////
/// Permet l'initialisation de la couleur du fond de la console et du texte
///////////////////////////////////////////////////////////
void CSLP_Color(CSLP_COLORTYPE txt, CSLP_COLORTYPE bg)
{
	CSLP_ColorText(txt);
	CSLP_ColorBG(bg);
}

/*
 * Fonctions pour récupérer les touches claviers pressées sans attendre
 * le '\n'. Equivalent de getch et kbhit de windows.h
 * (utilise CSLP_Thread*)
 */
#ifndef WIN32
//fonctions internes
//spécifiques à linux
//
//Permet la modification des propriétées du terminal
int SetTerm(bool org)
{
	static struct termios termAttr;
	bool error = false;

	//récupération des attributs du terminal
	if (tcgetattr(0, &termAttr) != 0)
	{
		error = true;
	}
	else
	{
		//vérification de l'ordre
		if (org)
		{
			//on rétablit l'echo lors d'une entrée et les
			//signaux basiques (EOF, ...)
			termAttr.c_lflag |= (ICANON|ECHO);
		}
		else
		{
			//on enlève les signaux basiques et l'affichage
			termAttr.c_lflag &= ~(ICANON|ECHO);
		}

		//initialisation des nouveaux attributs
		if (tcsetattr(0, TCSANOW, &termAttr) != 0)
		{
			error = true;
		}
	}
	return (int)(error);
}
#endif

//fonction externe
///////////////////////////////////////////////////////////
/// Permet d'attendre que l'utilisateur presse une touche
///////////////////////////////////////////////////////////
int CSLP_PollChar()
{
	int retVal = 0;
	#ifdef WIN32
	if (kbhit() != 0)
	{
		//touche appuyée et prette à être récupérée
		retVal = 1;
	}
	#else
	//initialisation des varaibles
	struct timeval sTime = {0, 0};
	fd_set readfds;
	FD_ZERO(&readfds);
	FD_SET(0, &readfds);
	//modifie les attributs du terminal
	if (SetTerm(false) != 0)
	{
		perror("Error: CSLP_PollChar can't initialize the terminal\n");
		retVal = -1;
	}
	else
	{
		retVal = select(1, &readfds, NULL, NULL, &sTime);
		//retVal = -1 	-> error
		//retVal = 0 	-> timeout
		//retVal > 0	-> event
	}
	#endif
	
	return retVal;
}

//fonction externe
//
///////////////////////////////////////////////////////////
/// Permet de récupérer la touche pressé par l'utilisateur
///////////////////////////////////////////////////////////
int CSLP_GetChar()
{
	char retVal = '\0';
	#ifdef WIN32
	if (kbhit() != 0)
	{
		//touche prette à être récupérée
		retVal = getch();
	}
	//si aucune touche n'a été appuyée, retval conserve sa valeur d'erreur '\0'
	#else
	//vérification de la présence d'une touche
	if (CSLP_PollChar() > 0)
	{
		//récupération de la touche
		retVal = getchar();
	}
	//rétablissement des paramètres par défaut du terminal
	if (SetTerm(true) != 0)
	{
		perror("Error: CSLP_GetChar can't initialize the terminal\n");
	}
	#endif
	return retVal;
}

///////////////////////////////////////////////////////////
/// Permet de récupérer la touche préssée par l'utilisateur.
///////////////////////////////////////////////////////////
int CSLP_WaitChar()
{
	int retVal;
	#ifdef WIN32
	retVal = getch();
	#else
	SetTerm(false);
	retVal = getchar();
	SetTerm(true);
	#endif
	return retVal;
}

